【高通SDM660平台 Android 10.0】(22)

您所在的位置:网站首页 flash q20ii闪光灯 【高通SDM660平台 Android 10.0】(22)

【高通SDM660平台 Android 10.0】(22)

2023-12-25 10:26| 来源: 网络整理| 查看: 265

【高通SDM660平台 Android 10.0】22 --- Flashlight 及 Kernel Flashlight 代码分析 一、[硬件] 闪光灯硬件原理图二、[vendor] 库文件 lib三、[vendor] 通用代码 flash.c 初始化3.1 module_sensor_flash_init()3.2 flash_process() 四、[Kernel] flashlight 驱动4.1 Kernel probe 初始化 msm_flash_platform_probe()4.2 CFG_FLASH_INIT 初始化闪光灯4.3 CFG_FLASH_LOW 开启手电筒或开启预闪4.4 CFG_FLASH_OFF 关闭闪光灯4.5 CFG_FLASH_HIGH 开启主闪

原创文章列表:

《【高通SDM660平台】(1) — Camera 驱动 Bringup Guide》 《【高通SDM660平台】(2) — Camera Kernel 驱动层代码逻辑分析》 《【高通SDM660平台】(3) — Camera V4L2 驱动层分析 》 《【高通SDM660平台】(4) — Camera Init 初始化流程 》 《【高通SDM660平台】(5) — Camera Open 流程》 《【高通SDM660平台】(6) — Camera getParameters 及 setParameters 流程》 《【高通SDM660平台】(7) — Camera onPreview 代码流程》 《【高通SDM660平台】(8) — Camera MetaData介绍》 《【高通SDM660平台 Android 10.0】(9) — Qcom Camera Daemon 代码分析》 《【高通SDM660平台 Android 10.0】(10) — Camera Sensor lib 与 Kernel Camera Probe 代码分析》 《【高通SDM660平台 Android 10.0】(11) — Eeprom lib 与 Kernel eeprom代码分析》 《【高通SDM660平台 Android 10.0】(12) — Camera Chromatix 代码分析》 《【高通SDM660平台 Android 10.0】(18) — Camera start_session() 过程分析》 《【高通SDM660平台 Android 10.0】(19) — Camera_focus、Camera_snapshot、volume_up 按键工作原理分析》 《【高通SDM660平台 Android 10.0】(20) — Actuator 与 Kernel Actuator代码分析》 《【高通SDM660平台 Android 10.0】(22) — Flashlight 及 Kernel Flashlight 代码分析》

一、[硬件] 闪光灯硬件原理图

本文以 mm-camera/mm-camera2/media-controller/modules/sensors/configs/sdm660_camera.xml 中的flash 为例, 先来看下原理图: 在这里插入图片描述

从原理图中可以看出,闪光灯的电 VDD_FLASH 及 开关控制引脚 FLASH_STROBE、FLASH_LED1、FLASH_LED2、FLASH_LED3 都是由 PM660L 来控制的。 其中 :

VDD_FLASH : 是主供电FLASH_STROBE : 手电筒模式时的PWM输出脚FLASH_LED1、FLASH_LED2、FLASH_LED3 : 闪光灯模式时的PWM输出脚,可以包含单闪、双闪需求

这个是一个方框图,由电池供电,经过升压,接着通过脉宽引脚的高电平来控制LED 的亮暗程度。。 在这里插入图片描述

所以整个原理是比较清晰的,代码方面要需对上述引脚做如下控制

闪光灯的上下电手电筒模式还是闪光灯模式根据亮度来控制PWM 输出的高电平脉宽占比 二、[vendor] 库文件 lib

从sdm660_camera.xml 中可以看出,pmic, 其代码位于:mm-camera/mm-camera2/media-controller/modules/sensors/flash/libs/pmic/pmic_flash.h,最终编译生成 libflash_pmic.so 库

在其头文件中:

# mm-camera/mm-camera2/media-controller/modules/sensors/flash/libs/pmic/pmic_flash.h #include "flash_lib.h" /* * if flash_driver_type is set to FLASH_DRIVER_DEFAULT * flash specifications are taken from kernel and the flash is driven by kernel. * For other value FLASH_DRIVER_PMIC / FLASH_DRIVER_GPIO * FLASH_DRIVER_I2C all the information like max current * max duration and num of flashes must be provided in this driver. */ static flash_lib_t flash_lib_ptr = { .flash_name = "pmic", .flash_driver_type = FLASH_DRIVER_TYPE_DEFAULT, .main_flash_on_frame_skip = 3, .main_flash_off_frame_skip = 3, .torch_on_frame_skip = 2, .torch_off_frame_skip = 2, };

头文件中主要是定义了在闪光灯打开时,摄像头需要跳过的帧数,及在手机筒打开时需要跳过的帧数。 还是一个比较重要的就是 flash_driver_type,

当 .flash_driver_type = FLASH_DRIVER_TYPE_DEFAULT, 时,闪光灯的相关配置是由kernel 来定义的。当 .flash_driver_type = FLASH_DRIVER_PMIC, 和其他值时,闪光灯的相关配置需要由本lib 库来定义。 三、[vendor] 通用代码 flash.c 初始化

在前在 《【高通SDM660平台 Android 10.0】(18) — Camera start_session() 过程分析》 中,我们分析过了, flash open动作是在 module_sensor_offload_open()中调用打开 闪光灯节点的。 flash 初始化是由 module_sensor_offload_init_config() 中来调用的。

void module_sensor_offload_init_config( void* param1, void* param2, void* param3 __attribute__((unused)), void* param4 __attribute__((unused))) { // 初始化闪光灯 ,调用 flash_init(),打开闪光灯 lib 库 SLOW("flash subdev id = %d", status = module_sensor_flash_init(s_bundle); // 获取使用闪光灯时,跳过的帧数,如果没设置,默认过滤 2 帧 /* Get led frame skip timing parameters */ SENSOR_SUB_MODULE_PROCESS_EVENT(s_bundle, SUB_MODULE_LED_FLASH, LED_FLASH_GET_FRAME_SKIP_TIME_PARAMS, s_bundle, rc); if (rc /* Get flash name from camera config read from daemon init */ a_name = s_bundle->sensor_common_info.camera_config.flash_name; SENSOR_SUB_MODULE_PROCESS_EVENT(s_bundle, SUB_MODULE_LED_FLASH, LED_FLASH_INIT, a_name, rc); return TRUE; }

可以看出,在 module_sensor_flash_init() 中主要是调用 flash_init() 来做初始化的。

case LED_FLASH_INIT: rc = flash_init(flash_ctrl, data); goto flash_process_Exit;

我们来看下 flash_init() 的内容。

根据传递的name ,拼凑lib 库的字符串,此处为 libflash_pmic.so,同步将 pmic_flash.h中的结构体内容保存在 flash_ptr->driver_lib_data 中。解析 pmic 参数信息,及 flash_driver_type 信息。配置 I2C 地址信息解析上下电信息,准备下发到 Kernel 中下发 CFG_FLASH_INIT 命令到 Kernel 中,相关信息保存在 .flash_init_info 中 static int32_t flash_init(void *ptr, void *data) { sensor_flash_data_t *flash_ctrl = (sensor_flash_data_t*)ptr; struct msm_flash_init_info_t flash_init_info; struct msm_flash_cfg_data_t flash_cfg; struct msm_camera_i2c_reg_setting_array *flash_init_settings = NULL; struct msm_sensor_power_setting_array *power_setting_array = NULL; SDBG("Enter"); /* memset flash init info */ memset(&flash_init_info, 0, sizeof(flash_init_info)); // 1. 根据传递的name ,拼凑lib 库的字符串,此处为 libflash_pmic.so,同步将 pmic_flash.h中的结构体内容保存在 flash_ptr->driver_lib_data 中 /* Load flash library */ rc = flash_load_lib(ptr, name); // 2. 解析 pmic 参数信息。 flash_update_settings_size(flash_ctrl->driver_lib_data); // 3. 解析 flash_driver_type 信息 switch (flash_ctrl->driver_lib_data->flash_driver_type) { case FLASH_DRIVER_TYPE_PMIC: flash_init_info.flash_driver_type = FLASH_DRIVER_PMIC; break; case FLASH_DRIVER_TYPE_I2C: flash_init_info.flash_driver_type = FLASH_DRIVER_I2C; break; case FLASH_DRIVER_TYPE_GPIO: flash_init_info.flash_driver_type = FLASH_DRIVER_GPIO; break; case FLASH_DRIVER_TYPE_DEFAULT: flash_init_info.flash_driver_type = FLASH_DRIVER_DEFAULT; break; } // 4. 配置I2C 地址 flash_init_info.slave_addr = flash_ctrl->driver_lib_data->i2c_flash_info.slave_addr; flash_init_info.i2c_freq_mode = sensor_sdk_util_get_i2c_freq_mode( flash_ctrl->driver_lib_data->i2c_flash_info.i2c_freq_mode); // 5. 解析上下电信息,准备下发到 Kernel 中 /* Translate power settings from uspace structure to kernel struct */ power_setting_array = (struct msm_sensor_power_setting_array *)malloc(sizeof(*power_setting_array)); translate_camera_power_setting(power_setting_array,&(flash_ctrl->driver_lib_data->power_setting_array)); /* Translate reg array settings from uspace structure to kernel struct */ flash_init_settings = (struct msm_camera_i2c_reg_setting_array *)malloc(sizeof(*flash_init_settings)); translate_sensor_reg_setting_array(flash_init_settings, &(flash_ctrl->driver_lib_data->i2c_flash_info.flash_init_settings)); flash_init_info.power_setting_array = power_setting_array; flash_init_info.settings = flash_init_settings; for (i = 0; i flash_ctrl->flash_max_current[i] = flash_cfg.flash_current[i]; flash_ctrl->flash_max_duration[i] = flash_cfg.flash_duration[i]; SLOW("i = %d flash_max_current = %d flash_max_duration = %d", i, flash_ctrl->flash_max_current[i], flash_ctrl->flash_max_duration[i]); } SDBG("Exit"); free(power_setting_array); free(flash_init_settings); return SENSOR_SUCCESS; } 3.2 flash_process()

flash_process() 是 flashlight 的核心函数

# mm-camera/mm-camera2/media-controller/modules/sensors/flash/module/flash.c static int32_t flash_process(void *ctrl, sensor_submodule_event_type_t event, void *data) { flash_ctrl = (sensor_flash_data_t *)ctrl; rer = flash_ctrl->rer; dual_led_setting = &flash_ctrl->dual_led_setting; /* Initilize to invalid value * Kernel uses default values if not updated */ cfg.flash_current[0] = default_current; cfg.flash_current[1] = default_current; /* Translate reg array settings from uspace structure to kernel struct */ flash_settings = (struct msm_camera_i2c_reg_setting_array *)malloc( sizeof(*flash_settings)); SLOW("event %d", event); switch (event) { case LED_FLASH_GET_MAX_CURRENT: { // 1. 获得闪光灯的最大电流 int32_t ** flash_current = (int32_t **)data; *flash_current = &(flash_ctrl->flash_max_current[0]); goto flash_process_Exit; } case LED_FLASH_GET_MAX_DURATION: { // 2. 获得双闪的最大电流 uint32_t* flash_duration = (uint32_t*)data; *flash_duration = flash_ctrl->flash_max_duration[0]; goto flash_process_Exit; } case LED_FLASH_SET_CURRENT: { // 3. 设置闪光灯的最大电流 /* Get currents for dual LED */ rc = flash_set_current(data, dual_led_setting); goto flash_process_Exit; } case LED_FLASH_INIT: // 4. 闪光灯初始化 rc = flash_init(flash_ctrl, data); goto flash_process_Exit; case LED_FLASH_SET_RER_CHROMATIX: { // 5. 设置 红眼 chromatix 参数 rer_chromatix = (red_eye_reduction_type *)data; /* Get (RER) data from chromatix */ rc = flash_rer_set_chromatix(rer, rer_chromatix); goto flash_process_Exit; } case LED_FLASH_GET_RER_PARAMS: { // 6. 获取 红眼 参数 *(int32_t *) data = rer->cfg->red_eye_reduction_led_flash_enable; goto flash_process_Exit; } case LED_FLASH_SET_RER_PARAMS: { // 7. 设置 红眼 参数 mode = (int32_t *)data; rc = flash_rer_set_parm(rer, *mode); goto flash_process_Exit; } case LED_FLASH_SET_FIRING_POWER:{ // 8. 设置电流 flashPower = *(uint8_t *)data; goto flash_process_Exit; } case LED_FLASH_SET_RER_PROCESS: { // 9. 配置红眼处理函数 led_module_params = (module_sensor_params_t *)data; rc = flash_rer_sequence_process(rer, led_module_params); goto flash_process_Exit; } case LED_FLASH_SET_OFF: // 10. 关闭闪光灯 SHIGH("Turning off flash"); translate_sensor_reg_setting_array(flash_settings, &(flash_ctrl->driver_lib_data->i2c_flash_info.flash_off_settings)); cfg.cfg_type = CFG_FLASH_OFF; cfg.cfg.settings = flash_settings; break; case LED_FLASH_SET_TORCH: case LED_FLASH_SET_PRE_FLASH: { // 11. 开启 手电筒 或 开启预闪,下发参数 CFG_FLASH_LOW SHIGH("Turning on torch/pre flash"); /* Pre flash mode */ translate_sensor_reg_setting_array(flash_settings, &(flash_ctrl->driver_lib_data->i2c_flash_info.flash_low_settings)); cfg.cfg_type = CFG_FLASH_LOW; cfg.cfg.settings = flash_settings; if (dual_led_setting->low_setting[0] == 0 && dual_led_setting->low_setting[1] == 0) { cfg.flash_current[0] = data ? *(int32_t *)data : default_current; cfg.flash_current[1] = data ? *(int32_t *)data : default_current; } else { cfg.flash_current[0] = dual_led_setting->low_setting[0]; cfg.flash_current[1] = dual_led_setting->low_setting[1]; } break; } case LED_FLASH_SET_RER_PULSE_FLASH: { // 12. 设置红眼 脉冲 电平 /* RER flash pulses */ translate_sensor_reg_setting_array(flash_settings, &(flash_ctrl->driver_lib_data->i2c_flash_info.flash_high_settings)); cfg.cfg_type = CFG_FLASH_HIGH; /* Use chromatix current if exist (set in RER_PROCESS)*/ cfg.flash_current[0] = data ? *(int32_t *)data : default_current; cfg.flash_current[1] = data ? *(int32_t *)data : default_current; cfg.cfg.settings = flash_settings; temp = (dual_led_setting->high_setting[0] + dual_led_setting->high_setting[1]); if (temp > 0) { /* Update with Dual LED current */ cfg.flash_current[0] = (cfg.flash_current[0] * dual_led_setting->high_setting[0]) / temp; cfg.flash_current[1] = (cfg.flash_current[1] * dual_led_setting->high_setting[1]) / temp; } break; } case LED_FLASH_SET_MAIN_FLASH: { // 13. 开启主闪 SHIGH("Turning on main flash"); /* Main flash mode */ translate_sensor_reg_setting_array(flash_settings, &(flash_ctrl->driver_lib_data->i2c_flash_info.flash_high_settings)); cfg.cfg_type = CFG_FLASH_HIGH; cfg.cfg.settings = flash_settings; if (dual_led_setting->high_setting[0] == 0 && dual_led_setting->high_setting[1] == 0) { cfg.flash_current[0] = data ? *(int32_t *)data : default_current; cfg.flash_current[1] = data ? *(int32_t *)data : default_current; } else { cfg.flash_current[0] = dual_led_setting->high_setting[0]; cfg.flash_current[1] = dual_led_setting->high_setting[1]; } rc = flash_rer_wait_pupil_contract(rer, led_module_params); break; } case LED_FLASH_GET_FRAME_SKIP_TIME_PARAMS: // 14. 获取 帧数过滤 参数 { module_sensor_bundle_info_t* s_bundle = (module_sensor_bundle_info_t*)data; rc = flash_get_frame_skip_timing_params(s_bundle,flash_ctrl); goto flash_process_Exit; } } rc = ioctl(flash_ctrl->fd, VIDIOC_MSM_FLASH_CFG, &cfg); flash_process_Exit: free(flash_settings); return rc; }

可以看出,操作闪光灯,都是操作 flash_process() 函数,最终都是通过 ioctl 来下发指令和参数的,还是比较好理解的。 接下来我们来看下 Kernel 中的代码。

四、[Kernel] flashlight 驱动 4.1 Kernel probe 初始化 msm_flash_platform_probe() # msm-4.14/arch/arm64/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi &soc { led_flash0: qcom,camera-flash@0 { cell-index = ; compatible = "qcom,camera-flash"; qcom,flash-source = ; qcom,torch-source = ; qcom,switch-source = ; status = "ok"; }; led_flash1: qcom,camera-flash@1 { cell-index = ; compatible = "qcom,camera-flash"; qcom,flash-source = ; qcom,torch-source = ; qcom,switch-source = ; status = "ok"; };

对应的c 代码位于: msm-4.14/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c

static const struct of_device_id msm_flash_dt_match[] = { {.compatible = "qcom,camera-flash", .data = NULL}, {} }; MODULE_DEVICE_TABLE(of, msm_flash_dt_match); static struct platform_driver msm_flash_platform_driver = { .probe = msm_flash_platform_probe, .driver = { .name = "qcom,camera-flash", .owner = THIS_MODULE, .of_match_table = msm_flash_dt_match, }, };

主要工作流程:

解析dts 信息,包括 cell-index、qcom,cci-master、qcom,switch-source、qcom,flash-source、qcom,max-current、qcom,duration 等。初始化V4L2 subdev,节点名为 /dev/v4l-subdevX如果type = FLASH_DRIVER_PMIC, 会对每一个 touch_source 注册为 led 设备,创建一个sys 节点, qcom,led-name = "led:torch_0"; static int32_t msm_flash_platform_probe(struct platform_device *pdev) { struct msm_flash_ctrl_t *flash_ctrl = NULL; struct msm_camera_cci_client *cci_client = NULL; flash_ctrl = kzalloc(sizeof(struct msm_flash_ctrl_t), GFP_KERNEL); memset(flash_ctrl, 0, sizeof(struct msm_flash_ctrl_t)); flash_ctrl->pdev = pdev; // 1. 解析dts 信息,包括 cell-index、qcom,cci-master、 // qcom,switch-source、qcom,flash-source、qcom,max-current、qcom,duration // qcom,torch-source、qcom,gpio-vana、qcom,gpio-vio、qcom,gpio-vaf、qcom,gpio-vdig、qcom,gpio-reset // qcom,gpio-standby、qcom,gpio-af-pwdm、qcom,gpio-flash-en、qcom,gpio-flash-reset rc = msm_flash_get_dt_data(pdev->dev.of_node, flash_ctrl); // 2. 初始化 V4L2 subdev,节点名为 /dev/v4l-subdevX flash_ctrl->flash_state = MSM_CAMERA_FLASH_RELEASE; flash_ctrl->power_info.dev = &flash_ctrl->pdev->dev; flash_ctrl->flash_device_type = MSM_CAMERA_PLATFORM_DEVICE; flash_ctrl->flash_mutex = &msm_flash_mutex; flash_ctrl->flash_i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl; flash_ctrl->flash_i2c_client.cci_client = kzalloc( sizeof(struct msm_camera_cci_client), GFP_KERNEL); cci_client = flash_ctrl->flash_i2c_client.cci_client; cci_client->cci_subdev = msm_cci_get_subdev(); cci_client->cci_i2c_master = flash_ctrl->cci_i2c_master; /* Initialize sub device */ v4l2_subdev_init(&flash_ctrl->msm_sd.sd, &msm_flash_subdev_ops); v4l2_set_subdevdata(&flash_ctrl->msm_sd.sd, flash_ctrl); flash_ctrl->msm_sd.sd.internal_ops = &msm_flash_internal_ops; flash_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; snprintf(flash_ctrl->msm_sd.sd.name, ARRAY_SIZE(flash_ctrl->msm_sd.sd.name),"msm_camera_flash"); media_entity_pads_init(&flash_ctrl->msm_sd.sd.entity, 0, NULL); flash_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_FLASH; flash_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1; msm_sd_register(&flash_ctrl->msm_sd); CDBG("%s:%d flash sd name = %s", __func__, __LINE__, flash_ctrl->msm_sd.sd.entity.name); msm_cam_copy_v4l2_subdev_fops(&msm_flash_v4l2_subdev_fops); #ifdef CONFIG_COMPAT msm_flash_v4l2_subdev_fops.compat_ioctl32 = msm_flash_subdev_fops_ioctl; #endif flash_ctrl->msm_sd.sd.devnode->fops = &msm_flash_v4l2_subdev_fops; // 3. 如果 type = FLASH_DRIVER_PMIC, // 会对每一个 touch_source 注册为 led 设备,创建一个sys 节点, qcom,led-name = "led:torch_0"; if (flash_ctrl->flash_driver_type == FLASH_DRIVER_PMIC) rc = msm_torch_create_classdev(pdev, flash_ctrl); =========> for (i = 0; i torch_num_sources; i++) { if (fctrl->torch_trigger[i]) { led_classdev_register(&pdev->dev, &msm_torch_led[i]); -----> ret = led_add_brightness_hw_changed(led_cdev); led_update_brightness(led_cdev); led_init_core(led_cdev); led_trigger_set_default(led_cdev); } switch (flash_data->cfg_type) { case CFG_FLASH_INIT: rc = msm_flash_init_prepare(flash_ctrl, flash_data); break; } rc = msm_flash_prepare(flash_ctrl); }

在 msm_flash_init_prepare() 中主要是,保存闪光灯电流参数,及保存上层下发的所有参数

static int32_t msm_flash_init_prepare(struct msm_flash_ctrl_t *flash_ctrl, struct msm_flash_cfg_data_t *flash_data) { struct msm_flash_cfg_data_t flash_data_k; struct msm_flash_init_info_t flash_init_info; int32_t i = 0; flash_data_k.cfg_type = flash_data->cfg_type; for (i = 0; i pr_err("%s copy_from_user failed %d\n",__func__, __LINE__); return -EFAULT; } return msm_flash_init(flash_ctrl, &flash_data_k); }

接着调用 msm_flash_init(), 在函数中,通过 camera_flash_init() 函数来下发参数, 初始化 flash_state = MSM_CAMERA_FLASH_INIT。

# msm-4.14/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c static int32_t msm_flash_init(struct msm_flash_ctrl_t *flash_ctrl,struct msm_flash_cfg_data_t *flash_data) { uint32_t i = 0; int32_t rc = -EFAULT; enum msm_flash_driver_type flash_driver_type = FLASH_DRIVER_DEFAULT; CDBG("Enter"); if (flash_data->cfg.flash_init_info->flash_driver_type == FLASH_DRIVER_DEFAULT) { flash_driver_type = flash_ctrl->flash_driver_type; for (i = 0; i flash_driver_type = flash_ctrl->flash_driver_type; for (i = 0; i if (flash_driver_type == flash_table[i]->flash_driver_type) { flash_ctrl->func_tbl = &flash_table[i]->func_tbl; rc = 0; } } if (flash_ctrl->func_tbl->camera_flash_init) { rc = flash_ctrl->func_tbl->camera_flash_init(flash_ctrl, flash_data); } flash_ctrl->flash_state = MSM_CAMERA_FLASH_INIT; CDBG("Exit"); return 0; }

camera_flash_init定义如下: 可以看出,当使和pmic 时,是不需要进行 camera_flash_init() 的,函数 为空。 如果走的是 gpio ,就会开始关闭所有的gpio,详细可以自行分析 msm_flash_gpio_init()。 如果 i2c ,则会初始化上电,然后通过 i2c 定义闪光灯相关的配置。

#msm-4.14/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c static struct msm_flash_table msm_pmic_flash_table = { .flash_driver_type = FLASH_DRIVER_PMIC, .func_tbl = { .camera_flash_init = NULL, .camera_flash_release = msm_flash_release, .camera_flash_off = msm_flash_off, .camera_flash_low = msm_flash_low, .camera_flash_high = msm_flash_high, .camera_flash_query_current = msm_flash_query_current, }, }; static struct msm_flash_table msm_gpio_flash_table = { .flash_driver_type = FLASH_DRIVER_GPIO, .func_tbl = { .camera_flash_init = msm_flash_gpio_init, .camera_flash_release = msm_flash_release, .camera_flash_off = msm_flash_off, .camera_flash_low = msm_flash_low, .camera_flash_high = msm_flash_high, .camera_flash_query_current = NULL, }, }; static struct msm_flash_table msm_i2c_flash_table = { .flash_driver_type = FLASH_DRIVER_I2C, .func_tbl = { .camera_flash_init = msm_flash_i2c_init, .camera_flash_release = msm_flash_i2c_release, .camera_flash_off = msm_flash_i2c_write_setting_array, .camera_flash_low = msm_flash_i2c_write_setting_array, .camera_flash_high = msm_flash_i2c_write_setting_array, .camera_flash_query_current = NULL, }, };

最终,还会调用 rc = msm_flash_prepare(flash_ctrl); switch_trigger 对应的就是 dts 中的 qcom,switch-source = ; 其内容如下:

pm660l_switch0: qcom,led_switch_0 { label = "switch"; qcom,led-name = "led:switch_0"; qcom,led-mask = ; qcom,default-led-trigger = "switch0_trigger"; };

我们来看下 msm_flash_prepare 的代码,在代码中,就是 通过 switch 进行上电。

static int32_t msm_flash_prepare(struct msm_flash_ctrl_t *flash_ctrl) { if (flash_ctrl->switch_trigger == NULL) { pr_err("%s:%d Invalid argument\n",__func__, __LINE__); return -EINVAL; } // 1. 上电 if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT && flash_ctrl->is_regulator_enabled == 0) { ret = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, ENABLE_REGULATOR, NULL); flash_ctrl->is_regulator_enabled = 1; } else if (flash_ctrl->flash_state == MSM_CAMERA_FLASH_RELEASE && flash_ctrl->is_regulator_enabled) { ret = qpnp_flash_led_prepare(flash_ctrl->switch_trigger,DISABLE_REGULATOR, NULL); flash_ctrl->is_regulator_enabled = 0; } CDBG("%s:%d:Exit\n", __func__, __LINE__); return ret; }

看下 qpnp_flash_led_prepare() 代码: 有关 led 子系统的代码,可以分析下 msm-4.14/drivers/leds/leds-qpnp-flash-v2.c,有机会我们后面分析, 今天主要分析闪光灯的流程,点到为止,不然篇幅会太长了。

int qpnp_flash_led_prepare(struct led_trigger *trig, int options,int *max_current) { // 通过 led:switch_0 名字,找到 led dev设备 led_cdev = trigger_to_lcdev(trig); // 上电 rc = qpnp_flash_led_regulator_control(led_cdev, options, max_current); return rc; } 4.3 CFG_FLASH_LOW 开启手电筒或开启预闪 static int32_t msm_flash_config(struct msm_flash_ctrl_t *flash_ctrl, void *argp) { case CFG_FLASH_LOW: if ((flash_ctrl->flash_state == MSM_CAMERA_FLASH_OFF) || (flash_ctrl->flash_state == MSM_CAMERA_FLASH_INIT)) { rc = flash_ctrl->func_tbl->camera_flash_low(flash_ctrl, flash_data); } break; }

接下来,我们进入 msm_flash_low() 函数看下, 通过 led_trigger_event() 来点亮。

static int32_t msm_flash_low(struct msm_flash_ctrl_t *flash_ctrl,struct msm_flash_cfg_data_t *flash_data) { CDBG("Enter\n"); /* Turn off flash triggers */ for (i = 0; i flash_num_sources; i++) if (flash_ctrl->flash_trigger[i]) led_trigger_event(flash_ctrl->flash_trigger[i], 0); /* Turn on flash triggers */ for (i = 0; i torch_num_sources; i++) { if (flash_ctrl->torch_trigger[i]) { max_current = flash_ctrl->torch_max_current[i]; if (flash_data->flash_current[i] >= 0 && flash_data->flash_current[i] curr = flash_ctrl->torch_op_current[i]; pr_debug("LED current clamped to %d\n", curr); } CDBG("low_flash_current[%d] = %d", i, curr); led_trigger_event(flash_ctrl->torch_trigger[i], curr); } } if (flash_ctrl->switch_trigger) led_trigger_event(flash_ctrl->switch_trigger, 1); CDBG("Exit\n"); return 0; } 4.4 CFG_FLASH_OFF 关闭闪光灯 case CFG_FLASH_OFF: rc = flash_ctrl->func_tbl->camera_flash_off(flash_ctrl, flash_data);

很好理解,通过 led_trigger_event() 来触发 关闭

static int32_t msm_flash_off(struct msm_flash_ctrl_t *flash_ctrl,struct msm_flash_cfg_data_t *flash_data) { int32_t i = 0; CDBG("Enter\n"); for (i = 0; i flash_num_sources; i++) if (flash_ctrl->flash_trigger[i]) led_trigger_event(flash_ctrl->flash_trigger[i], 0); for (i = 0; i torch_num_sources; i++) if (flash_ctrl->torch_trigger[i]) led_trigger_event(flash_ctrl->torch_trigger[i], 0); if (flash_ctrl->switch_trigger) led_trigger_event(flash_ctrl->switch_trigger, 0); CDBG("Exit\n"); return 0; } 4.5 CFG_FLASH_HIGH 开启主闪 case CFG_FLASH_HIGH: rc = flash_ctrl->func_tbl->camera_flash_high(flash_ctrl, flash_data); static int32_t msm_flash_high( struct msm_flash_ctrl_t *flash_ctrl, struct msm_flash_cfg_data_t *flash_data) { /* Turn off torch triggers */ for (i = 0; i torch_num_sources; i++) if (flash_ctrl->torch_trigger[i]) led_trigger_event(flash_ctrl->torch_trigger[i], 0); /* Turn on flash triggers */ for (i = 0; i flash_num_sources; i++) { if (flash_ctrl->flash_trigger[i]) { max_current = flash_ctrl->flash_max_current[i]; if (flash_data->flash_current[i] >= 0 && flash_data->flash_current[i] curr = flash_ctrl->flash_op_current[i]; pr_debug("LED flash_current[%d] clamped %d\n", i, curr); } CDBG("high_flash_current[%d] = %d", i, curr); led_trigger_event(flash_ctrl->flash_trigger[i], curr); } } if (flash_ctrl->switch_trigger) led_trigger_event(flash_ctrl->switch_trigger, 1); return 0; }

好啦,闪光灯代码,就先看到这里,前面逻辑还是比较好理解的, 后面到了kernel 层,主要就是led 子系统的工作了,由它来实现点亮和关闭灯。

后面有时间,我们再来单独分析下,LED 子系统。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3